/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   Module Name          : com.yaodian100.ec.coupon.service.impl.CouponServiceImpl
   Module Description   :

   Date Created      : 2009/11/25
   Original Author   : jeff.ma
   Team              : yaodian100
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   MODIFICATION HISTORY
   ------------------------------------------------------------------------------
   Date Modified       Modified by       Comments
   ------------------------------------------------------------------------------
   ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
package com.yaodian100.ec.coupon.service.impl;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.hibernate.Hibernate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.security.providers.encoding.ShaPasswordEncoder;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.yaodian100.core.common.dao.ObjectDao;
import com.yaodian100.core.common.dao.impl.CommonCriteria;
import com.yaodian100.core.common.exception.CoreException;
import com.yaodian100.core.common.service.impl.DomainServiceImpl;
import com.yaodian100.core.common.utils.DateUtil;
import com.yaodian100.core.common.utils.ServerValue;
import com.yaodian100.core.mail.entity.Mail;
import com.yaodian100.core.mail.service.MailService;
import com.yaodian100.core.template.service.TemplateService;
import com.yaodian100.ec.common.EnvParameters;
import com.yaodian100.ec.coupon.entity.Coupon;
import com.yaodian100.ec.coupon.entity.CouponItem;
import com.yaodian100.ec.coupon.service.CouponService;
import com.yaodian100.ec.member.entity.Member;
import com.yaodian100.ec.member.service.MemberService;
import com.yaodian100.ec.order.entity.OrderProduct;
import com.yaodian100.ec.order.entity.Orders;
import com.yaodian100.ec.shopping.entity.CartOrderProduct;

/**
 * @author jeff.ma
 * 
 */
public class CouponServiceImpl extends DomainServiceImpl<Coupon> implements CouponService {
	private static final String FIELD_NAME_MEMBER_ID = "memberId";
	private static final String FIELD_NAME_COUPON = "coupon";
	@Resource
	private TemplateService velocityService;
	@Resource
	private MailService mailService;
	@Resource
	private MemberService memberService;
	@Resource
	private EnvParameters envParameters;
	@Resource
	private JdbcTemplate jdbcTemplate;
	private ObjectDao<CouponItem> itemDao;
	private final PasswordEncoder encoder = new ShaPasswordEncoder();

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#generate(com.yaodian100.ec.coupon.entity.Coupon, java.io.File)
	 */
	@Override
	@Transactional(readOnly = false)
	public Coupon generate(Coupon coupon, File file, String isSendMail, Date startDate, Date endDate)
			throws CoreException {
		long count = 0;
		if (!Coupon.Status.INIT.equals(coupon.getStatus())) {
			throw new CoreException(CouponService.ERROR_COUPON_ISUSED);
		} else if (coupon == null) {
			return coupon;
		}
		// clean old coupon item
		if (coupon.getUuid() != null) {
			Map<String, Serializable> attrs = new HashMap<String, Serializable>();
			attrs.put("couponUuid", coupon.getUuid());
			itemDao.executeUpdate("CouponItem.cleanByCoupon", attrs);
		} else {

			save(coupon);
		}

		Date now = new Date(System.currentTimeMillis());
		String nextCode = encoder.encodePassword(now.toString(), null).substring(0, 10);
		if (file == null) {
			for (long i = coupon.getAmount(); i > 0; i--) {
				CouponItem item = new CouponItem(coupon);
				item.setCode(nextCode);
				item.setStartDate(startDate);
				item.setEndDate(endDate);
				itemDao.save(item);
				nextCode = encoder.encodePassword(item.getUuid(), null).substring(0, 10);
			}
			count = coupon.getAmount();
		} else {
			LineNumberReader reader = null;
			List ltmember = new ArrayList();
			try {
				reader = new LineNumberReader(new FileReader(file));
				while (reader.ready()) {
					String str = reader.readLine();
					if (StringUtils.isNotEmpty(str)) {
						String memberId = StringUtils.trimToEmpty(str);
						CouponItem item = new CouponItem(coupon, memberId, now);
						item.setCode(nextCode);
						item.setStartDate(startDate);
						item.setEndDate(endDate);
						itemDao.save(item);
						nextCode = encoder.encodePassword(item.getUuid(), null).substring(0, 10);
						ltmember.add(memberId);
						count++;
					}
				}
				if ("Y".equals(isSendMail) && count > 0) {
					sendMemberMail("couponGenerateMail", ltmember, coupon, endDate);
				}
				if (count > 0) {
					if (Coupon.Status.INIT.equals(coupon.getStatus())) {
						// 如果已經發出禮券，就要改變狀態，讓禮券不能被重新產生和刪除
						coupon.setStatus(Coupon.Status.USED);
					}
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			coupon.setAmount(count);
			save(coupon);
		}
		return coupon;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#getItem(java.lang.String)
	 */
	@Override
	public CouponItem getItem(String itemUuid) throws CoreException {
		CouponItem result = itemDao.get(itemUuid);
		if (result != null) {
			Hibernate.initialize(result.getCoupon());
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#getItems(java.lang.Long)
	 */
	@Override
	public List<CouponItem> getItems(String memberId) throws CoreException {
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("couponStatus", Coupon.Status.INACTIVE);
		attrs.put("nowDate", new Date(System.currentTimeMillis()));
		return itemDao.getNameQuery("CouponItem.getMemberFreeItems", attrs, 0, -1);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<CouponItem> getListItems(String memberId) throws CoreException {
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("couponStatus", Coupon.Status.INACTIVE);
		attrs.put("nowDate", new Date(System.currentTimeMillis()));
		attrs.put("endDate", DateUtils.addMonths(new Date(), -6));
		return itemDao.getNameQuery("CouponItem.getMemberListItems", attrs, 0, -1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#getWaitItems(java.lang.String)
	 */
	@Override
	public List<CouponItem> getWaitItems(String memberId) throws CoreException {
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("couponStatus", Coupon.Status.INACTIVE);
		attrs.put("nowDate", new Date(System.currentTimeMillis()));
		return itemDao.getNameQuery("CouponItem.getMemberFreeWaitItems", attrs, 0, -1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#getUsedItems(java.lang.String)
	 */
	@Override
	public List<CouponItem> getUsedItems(String memberId) throws CoreException {
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("limitedDate", DateUtils.addMonths(new Date(), -6));
		return itemDao.getNameQuery("CouponItem.getMemberUsedItems", attrs, 0, -1);
	}

	@SuppressWarnings("unchecked")
	@Override
	public String getFreeItemsTotal(String memberId) throws CoreException {
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("couponStatus", Coupon.Status.INACTIVE);
		attrs.put("nowDate", new Date(System.currentTimeMillis()));
		List couponList = itemDao.getNameQuery("CouponItem.getMemberFreeItemsTotal", attrs, 0, -1);
		if (null == couponList.get(0)) {
			return "0";
		}
		return couponList.get(0).toString();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#getItems(java.lang.Long, java.lang.Object)
	 */
	@Override
	public List<CouponItem> getItems(String memberId, List<OrderProduct> products) throws CoreException {
		List<CouponItem> allItems = getItems(memberId);
		List<CouponItem> validItems = new ArrayList<CouponItem>();
		// update item.products
		for (CouponItem item : allItems) {
			switch (item.getCoupon().getApplyRangeType()) {
			case ALL:
				for (OrderProduct product : products) {
					item.getProducts().add(product);
				}
				validItems.add(item);
				break;
			case CATEGORY:
				for (String typeExtension : item.getCoupon().getApplyRangeTypeExtensionArray()) {
					boolean isValid = false;
					for (OrderProduct product : products) {
						if (product.getCategoryPath().indexOf(typeExtension) != -1) {
							item.getProducts().add(product);
							isValid = true;
						}
					}
					if (isValid) {
						validItems.add(item);
					}
				}
				break;
			case PRODUCT:
				for (String typeExtension : item.getCoupon().getApplyRangeTypeExtensionArray()) {
					boolean isValid = false;
					for (OrderProduct product : products) {
						if (product.getProdId().equals(typeExtension)) {
							item.getProducts().add(product);
							isValid = true;
						}
					}
					if (isValid) {
						validItems.add(item);
					}
				}
				break;
			}
		}
		return validItems;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#isValid(com.yaodian100.ec.coupon.entity.CouponItem,
	 * com.yaodian100.ec.order.entity.OrderProduct)
	 */
	@Override
	public boolean isValid(CouponItem couponItem, OrderProduct product) throws CoreException {
		return isValid(couponItem, product.getProdId(), product.getCategoryPath());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#regCoupon(java.lang.String, java.lang.Long)
	 */
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public CouponItem regCoupon(String couponUuid, String memberId) throws CoreException {
		CouponItem item = null;
		Date now = new Date(System.currentTimeMillis());
		Coupon coupon = get(couponUuid);
		if (Coupon.Status.INACTIVE.equals(coupon.getStatus())) {
			throw new CoreException(CouponService.ERROR_COUPON_INACTIVE);
		}
		// 該禮券是否不允許同一會員取得多張優惠碼
		if (coupon.getIsOnce().booleanValue()) {
			List<CouponItem> couponItemsOfMember = getCouponItemListByCouponAndMember(coupon, memberService.get(memberId));
			if (couponItemsOfMember != null && couponItemsOfMember.size() > 0) {
				// fail
				logger.warn("regCoupon fail. memberId: {} already got coupon:{} ", new Object[] { memberId, couponUuid });
				return null;
			}
		}
		CommonCriteria cri = new CommonCriteria().addEq("coupon.uuid", couponUuid).addEq(FIELD_NAME_MEMBER_ID, null);
		// 改用 list page 取得 50 個未用 couponItem, 隨機取得一個
		List<CouponItem> items = itemDao.getListPageable(cri, null, 0, 50);
		if (items.size() > 1) {
			item = items.get(RandomUtils.nextInt(items.size()));
			if (!(item.getEndDate().after(now))) {
				throw new CoreException(CouponService.ERROR_COUPON_ISEXPIRED);
			}
		}
		if (item != null) {
			item.setMemberId(memberId);
			item.setRegDate(now);
			itemDao.saveOrUpdate(item);
		} else {
			logger.warn("memberId: {} get coupon:{} fail, size:{}", new Object[] { memberId, couponUuid, items.size() });
		}

		return item;
	}

	@Override
	public boolean getIsAvailable(String couponUuid) throws CoreException {
		CouponItem item = null;
		Date now = new Date(System.currentTimeMillis());
		Coupon coupon = get(couponUuid);
		if (Coupon.Status.INACTIVE.equals(coupon.getStatus())) {
			return false;
		}
		CommonCriteria cri = new CommonCriteria().addEq("coupon.uuid", couponUuid).addEq(FIELD_NAME_MEMBER_ID, null);
		item = itemDao.getSingle(cri, null);
		if (item != null && item.getEndDate().after(now)) {
			return true;
		}
		return false;
	}

	/**
	 * @author chin.hung
	 */
	@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
	public CouponItem regCouponItem(CouponItem couponItem, String memberId) throws CoreException {

		CouponItem couponItemInDb = getCouponItemByCode(couponItem.getCode());
		if (couponItemInDb == null) {
			throw new RuntimeException();
		}
		Date now = new Date(System.currentTimeMillis());
		if (!(couponItemInDb.getEndDate().after(now))) {
			throw new CoreException(CouponService.ERROR_COUPON_ISEXPIRED);
		}
		Coupon couponInDb = couponItemInDb.getCoupon();

		if (Coupon.Status.INACTIVE.equals(couponInDb.getStatus())) {
			throw new CoreException(CouponService.ERROR_COUPON_INACTIVE);
		}
		// 將 coupon 標記為已使用
		if (!Coupon.Status.USED.equals(couponInDb.getStatus())) {
			couponInDb.setStatus(Coupon.Status.USED);
			save(couponInDb);
		}
		// 將會員和充值日期寫到 coupon item 中
		if (couponItemInDb != null) {
			couponItemInDb.setMemberId(memberId);
			couponItemInDb.setRegDate(now);
			itemDao.saveOrUpdate(couponItemInDb);
		}

		return couponItemInDb;
	}

	/**
	 * @param itemDao the itemDao to set
	 */
	public void setItemDao(ObjectDao<CouponItem> itemDao) {
		this.itemDao = itemDao;
	}

	@Override
	@Transactional(readOnly = false)
	public void unuseCoupon(String orderId, String couponUuid) {
		try {
			CouponItem couponItem = queryCouponItemByOrderIdAndCouponUuid(orderId, couponUuid);
			couponItem.setOrderId(null);
			couponItem.setUseDate(null);
			// 到期日<=系統日+3，原到期日改為：取消隔日＋10
			DateFormat df = new SimpleDateFormat("yyyyMMdd");
			Date todays;
			todays = df.parse(df.format(new Date()));
			Date todaye = new SimpleDateFormat("yyyyMMddHHmmss").parse(df.format(todays) + "235959");
			if (couponItem.getEndDate().before(DateUtils.addDays(todaye, 3))) {
				if (this.checkOrderForUnuse(orderId)) {
					// couponItem.setStartDate(DateUtils.addDays(todays, 1));
					couponItem.setEndDate(DateUtils.addDays(todaye, 11));
				}
			}
			this.itemDao.saveOrUpdate(couponItem);
		} catch (Throwable e) {
			logger.error("unuseCoupon Exception : " + e.getMessage());
		}
	}

	private boolean checkOrderForUnuse(String orderId) throws Exception {
		String sql = "select count(*) from crm_question_ev where question_id in ( "
				+ "select question_id from crm_question_ev where name='orderId' and value=? "
				+ ") and name='cancelReason' and value in('10','20') ";
		int cnt = this.jdbcTemplate.queryForInt(sql, orderId);
		return (cnt > 1);
	}

	@Override
	@Transactional(readOnly = false)
	public void transferCoupon(Orders oldOrder, Orders newOrder, String couponUuid) {
		String newOrderId = newOrder.getOrderId();

		OrderProduct theOp = null;
		for (int i = 0; i < newOrder.getOrderProduct().size(); i++) {
			OrderProduct op = newOrder.getOrderProduct().get(i);
			if (op.getCouponId() != null) {
				theOp = op;
				break;
			}
		}
		try {
			this.forceUseCoupon(theOp.getCouponItemId(), oldOrder.getMemberId(), newOrder.getOrderId());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#useCoupon(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public void useCoupon(String itemUuid, String memberId, String orderId) throws CoreException {
		CouponItem item = itemDao.get(itemUuid);
		Date now = new Date(System.currentTimeMillis());
		if (item == null || item.getOrderId() != null) {
			throw new CoreException(CouponService.ERROR_COUPON_ISUSED, item == null ? "" : item.toString(), memberId, orderId);
		} else if (Coupon.Status.INACTIVE.equals(item.getCoupon().getStatus())) {
			throw new CoreException(CouponService.ERROR_COUPON_INACTIVE, item == null ? "" : item.toString(), memberId,
					orderId);
		} else if (!memberId.equals(item.getMemberId())) {
			throw new CoreException(CouponService.ERROR_COUPON_NOOWNER, item == null ? "" : item.toString(), memberId,
					orderId);
		} else if (!(item.getStartDate().before(now) && item.getEndDate().after(now))) {
			throw new CoreException(CouponService.ERROR_COUPON_ISEXPIRED, item == null ? "" : item.toString(), memberId,
					orderId);
		} else {
			item.setOrderId(orderId);
			item.setUseDate(now);
			itemDao.saveOrUpdate(item);

			Coupon coupon = item.getCoupon();
			if (!Coupon.Status.USED.equals(coupon.getStatus())) {
				coupon.setStatus(Coupon.Status.USED);
				save(coupon);
			}
		}
	}

	@Transactional(readOnly = false)
	public void forceUseCoupon(String itemUuid, String memberId, String orderId) throws Exception {
		CouponItem item = itemDao.get(itemUuid);
		Date now = new Date(System.currentTimeMillis());
		item.setMemberId(memberId);
		item.setOrderId(orderId);
		item.setUseDate(now);
		item = updateCouponItem(item, memberId);

		Coupon coupon = item.getCoupon();
		if (!Coupon.Status.USED.equals(coupon.getStatus())) {
			coupon.setStatus(Coupon.Status.USED);
			save(coupon);
		}

	}

	@Override
	@Transactional(readOnly = false)
	public CouponItem updateCouponItem(CouponItem item, String memberId) throws Exception {
		CouponItem ci = itemDao.saveOrUpdate(item);
		if (StringUtils.isNotBlank(memberId)) {
			memberService.reCalculateBalance(memberId);
		}
		return ci;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#isValid(com.yaodian100.ec.coupon.entity.CouponItem,
	 * com.yaodian100.ec.shopping.entity.CartOrderProduct)
	 */
	@Override
	public boolean isValid(CouponItem couponItem, CartOrderProduct product) throws CoreException {
		return isValid(couponItem, product.getProdId(), product.getCategoryPath());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#getAllItems(java.lang.String)
	 */
	@Override
	public List<CouponItem> getAllItems(String couponUuid) throws CoreException {
		CommonCriteria criteria = new CommonCriteria();
		criteria.addEq("coupon.uuid", couponUuid);
		return itemDao.getList(criteria, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#getListItems(java.lang.String, int, int)
	 */
	@Override
	public List<CouponItem> getListItems(String couponUuid, int startNode, int returnSize) throws CoreException {
		CommonCriteria criteria = new CommonCriteria();
		criteria.addEq("coupon.uuid", couponUuid);
		return itemDao.getListPageable(criteria, new String[] { "uuid asc" }, startNode, returnSize);
	}

	@Override
	public int getAllItemsSize(String couponUuid) throws CoreException {
		CommonCriteria criteria = new CommonCriteria();
		criteria.addEq("coupon.uuid", couponUuid);
		return itemDao.getListSize(criteria).intValue();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.coupon.service.CouponService#isValid(com.yaodian100.ec.coupon.entity.CouponItem,
	 * java.lang.String, java.lang.String)
	 */
	@Override
	public boolean isValid(CouponItem couponItem, String productId, String categoryPath) throws CoreException {
		boolean result = false;
		switch (couponItem.getCoupon().getApplyRangeType()) {
		case ALL:
			result = true;
			break;
		case CATEGORY:
			if (StringUtils.isNotBlank(categoryPath)) {
				for (String typeExtension : couponItem.getCoupon().getApplyRangeTypeExtensionArray()) {
					if (categoryPath.startsWith(typeExtension)) {
						result = true;
						break;
					}
				}
			}
			break;
		case PRODUCT:
			if (StringUtils.isNotBlank(productId)) {
				for (String typeExtension : couponItem.getCoupon().getApplyRangeTypeExtensionArray()) {
					if (productId.equals(typeExtension)) {
						result = true;
						break;
					}
				}
			}
			break;
		}
		return result;
	}

	/**
	 * @author chin.hung
	 * @param couponItemCode
	 */
	public CouponItem getCouponItemByCode(String couponItemCode) {
		CouponItem result = null;
		if (!StringUtils.isEmpty(couponItemCode)) {
			CommonCriteria criteria = new CommonCriteria();
			criteria.addEq("code", couponItemCode);
			result = itemDao.getSingle(criteria, null);
			if (result != null) {
				Hibernate.initialize(result.getCoupon());
			}
		}
		return result;
	}

	@Transactional(readOnly = false)
	public void sendMemberMail(String velocityTemplate, List ltmember, Coupon coupon, Date endDate) throws CoreException {
		try {
			Date dead3 = DateUtil.getTodayAddDays(1).getTime();
			dead3.setHours(1);
			dead3.setMinutes(0);
			dead3.setSeconds(0);
			Calendar cal = DateUtil.getTodayAddDays(1);
			cal.setTimeInMillis(dead3.getTime());
			cal.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, 1, 0);
			cal.setTimeInMillis(dead3.getTime());
			for (int i = 0; i < ltmember.size(); i++) {
				dead3 = cal.getTime();
				Member member = memberService.get(ltmember.get(i).toString());
				Map<String, Object> contentMap = new HashMap<String, Object>();
				contentMap.put("contextpath", ServerValue.getFrontContextPath());
				contentMap.put("basehref", "http://" + member.getDomainSrc());
				contentMap.put("endDate", FastDateFormat.getInstance("yyyy-MM-dd").format(endDate));
				contentMap.put("sysDate", FastDateFormat.getInstance("yyyy-MM-dd").format(dead3));
				contentMap.put(FIELD_NAME_COUPON, coupon);
				contentMap.put("member", member);
				Mail mail = velocityService.formatToMail(velocityTemplate, contentMap);
				mail.setTo(member.getSendEmail());
				mail.setFrom(envParameters.getEmailFromSystem());
				mail.setSubject("礼券发放通知 -" + coupon.getName() + "．耀点100");
				mail.setSendDT(dead3);
				mailService.save(mail);
				if ((i + 1) % 30 == 0) {
					cal.add(Calendar.MINUTE, 10);
				}
			}
		} catch (Exception e) {
			logger.error("err:" + e.getMessage());
		}
	}

	public List<CouponItem> getCouponItemListByCouponAndMember(Coupon coupon, Member member) {
		List<CouponItem> result = new ArrayList<CouponItem>();

		CommonCriteria criteria = new CommonCriteria();
		criteria.addEq(FIELD_NAME_COUPON, coupon);
		criteria.addEq(FIELD_NAME_MEMBER_ID, member.getMemberId());
		result = this.itemDao.getList(criteria, null);

		return result;
	}

	public void setVelocityService(TemplateService velocityService) {
		this.velocityService = velocityService;
	}

	public void setMailService(MailService mailService) {
		this.mailService = mailService;
	}

	public void setMemberService(MemberService memberService) {
		this.memberService = memberService;
	}

	public EnvParameters getEnvParameters() {
		return envParameters;
	}

	public void setEnvParameters(EnvParameters envParameters) {
		this.envParameters = envParameters;
	}

	private CouponItem queryCouponItemByOrderIdAndCouponUuid(String oldOrderId, String couponUuid) {
		CommonCriteria criteria = new CommonCriteria();
		criteria.addEq("coupon.uuid", couponUuid);
		criteria.addEq("orderId", oldOrderId);

		List<CouponItem> queryResult = this.itemDao.getList(criteria, null);
		if (queryResult == null || queryResult.size() <= 0) {
			throw new RuntimeException("查無 coupon uuid 與 order id 相符的 coupon item");
		}

		CouponItem couponItem = queryResult.get(0);
		return couponItem;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean updateStartEndDate(String coupon_uuid, Date startDate, Date endDate) {
		DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
		jdbcTemplate.execute("update EC_COUPON_ITEM set START_DATE = to_date('" + df.format(startDate)
				+ "', 'yyyyMMddhh24MIss'), END_DATE = to_date('" + df.format(endDate)
				+ "', 'yyyyMMddhh24MIss') where COUPON_UUID = '" + coupon_uuid + "'");
		return true;
	}

	@Override
	public List<Map<String, Object>> getItemLogs(String couponCode) throws CoreException {
		List<Map<String, Object>> lists = new ArrayList();
		try {
			StringBuffer sb = new StringBuffer();
			sb.append("select modify_date,order_id,end_date,log_type from ec_coupon_item_log");
			sb.append(" where coupon_code=?");
			sb.append(" order by modify_date desc ");
			lists = jdbcTemplate.queryForList(sb.toString(), couponCode);
		} catch (Exception e) {
			logger.error(e.toString());
		}
		return lists;
	}
}
